﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Net;
using System.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Logging;
using Microsoft.Practices.ObjectBuilder2;
using System.IO;
using System.Globalization;
using MaintenanceService.Common.Scheduler;

namespace MaintenanceService.WindowsService
{
    public partial class Service : ServiceBase
    {

        enum MaintenaceServiceEventTypes
        {
            SleepingTime = 1,
            ResponseValue = 2,
            GeneralInfo = 3,
            ResponseData = 4,
            Error = 100

        }
        enum MaintenacePriorityMessage
        {
            Low = 1,
            Medium = 50,
            High = 100
        }


        ServiceSchedulerObject _serviceScheduler;
        private static System.Timers.Timer aTimer;
        List<string> categoriesInfo = new List<string>();
        List<string> categoriesDebug = new List<string>();
        private string dirSite = String.Empty;

        public Service()
        {
            InitializeComponent();
            categoriesInfo.Add("Info");
            categoriesDebug.Add("Debug");
        }

        protected override void OnStart(string[] args)
        {
            var settings = System.Configuration.ConfigurationManager.AppSettings;
            dirSite = settings["dirSite"];
            StartScheduler();
            CreateLogEntryMessage(Properties.Resources.Start, String.Format(CultureInfo.CurrentCulture, Properties.Resources.ServiceStart),
                         MaintenaceServiceEventTypes.GeneralInfo, categoriesInfo, MaintenacePriorityMessage.Low, TraceEventType.Information);

        }

        private void StartScheduler()
        {
            //Scheduler
            _serviceScheduler = ServiceSchedulerFactory.GetServiceSchedulerObject();
            // Create a timer with a ten second interval.
            aTimer = new System.Timers.Timer();
            CalcularSleepTime(false, 120);
            // Hook up the Elapsed event for the timer.
            aTimer.Elapsed += new System.Timers.ElapsedEventHandler(aTimer_Elapsed);
            aTimer.Enabled = true;
        }

        private void CalcularSleepTime(bool arePendingTasks, double lastTaskDuration)
        {
            ServiceSchedulerArgs arg = new ServiceSchedulerArgs();
            arg.ArePendingTasks = arePendingTasks;
            arg.LastTaskDuration = Convert.ToInt32(Math.Ceiling(lastTaskDuration));

            int interval = _serviceScheduler.ServiceScheduler.GetServiceSleepTime(arg) * 1000;
            aTimer.Interval = interval;
        }
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        void aTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            aTimer.Enabled = false;
         
            //long length = 0;
            DateTime inicio = DateTime.Now;
            bool arePendingsTask = false;
            try
            {
                //Check Web Adress
                arePendingsTask = CheckWebAddress(arePendingsTask);
                //Database Tasks
                ExecuteAdditionalTasks();
                //Filesystem Taks
            }
            catch (Exception ex)
            {
                CreateLogEntryError(ex);

            }

            TimeSpan duracion = DateTime.Now.Subtract(inicio);
            CalcularSleepTime(arePendingsTask, duracion.TotalSeconds);
            CreateLogEntryMessage(Properties.Resources.SleepTime, String.Format(CultureInfo.CurrentCulture, Properties.Resources.SleepTime0, aTimer.Interval),
                               MaintenaceServiceEventTypes.SleepingTime, categoriesInfo, MaintenacePriorityMessage.Low, TraceEventType.Information);

            aTimer.Enabled = true;

        }

        private static void ExecuteAdditionalTasks()
        {
            using (Common.Dal.DalObject _repository = Common.Dal.DalFactory.GetDalObject())
            {
                var additionalTasks = _repository.Repository.GetAdditionalTasks();

                foreach (var item in additionalTasks)
                {

                    if (!String.IsNullOrEmpty(item.TaskInfo.AssemblyFullPath.Trim()))
                    {
                    }
                    else
                    {
                        if (!String.IsNullOrEmpty(item.TaskInfo.StoredProcedureName.Trim()))
                        {
                            _repository.Repository.ExecuteAdditionalTask(item.AdditionalTaskId);
                        }
                    }
                    
                }


            }
        }

        private bool CheckWebAddress(bool arePendingsTask)
        {
            if (!String.IsNullOrEmpty(dirSite))
            {

                CreateLogEntryMessage(Properties.Resources.WebAddress, String.Format(CultureInfo.CurrentCulture, Properties.Resources.WebAddress0, dirSite),
                                        MaintenaceServiceEventTypes.GeneralInfo, categoriesInfo, MaintenacePriorityMessage.Low, TraceEventType.Information);

                Uri targetUri = new Uri(dirSite);
                // Prepare web request...
                HttpWebRequest myRequest =
                  (HttpWebRequest)WebRequest.Create(targetUri);
                myRequest.Timeout = 1000 * 60 * 5;
                using (WebResponse response = myRequest.GetResponse())
                {
                    //length = response.ContentLength;

                    var filter = Logger.GetFilter<Microsoft.Practices.EnterpriseLibrary.Logging.Filters.CategoryFilter>();
                    if (filter != null && filter.ShouldLog(categoriesDebug))
                    {
                        StreamReader loResponseStream = new StreamReader(response.GetResponseStream());
                        string lcHtml = loResponseStream.ReadToEnd();
                        arePendingsTask = "+".Equals(lcHtml);
                        CreateLogEntryMessage(Properties.Resources.Response, String.Format(CultureInfo.CurrentCulture, Properties.Resources.Response0, lcHtml),
                            MaintenaceServiceEventTypes.ResponseData, categoriesDebug, MaintenacePriorityMessage.Low, TraceEventType.Information);
                    }


                }

                CreateLogEntryMessage(Properties.Resources.ArePendingsTasks, String.Format(CultureInfo.CurrentCulture, Properties.Resources.ArePendingsTasks0, arePendingsTask),
                MaintenaceServiceEventTypes.ResponseData, categoriesInfo, MaintenacePriorityMessage.Low, TraceEventType.Information);
                return arePendingsTask;
            }
            else
            {
                CreateLogEntryMessage(Properties.Resources.WebAddress, String.Format(CultureInfo.CurrentCulture, Properties.Resources.NoWebAddress),
                        MaintenaceServiceEventTypes.GeneralInfo, categoriesInfo, MaintenacePriorityMessage.Low, TraceEventType.Information);
                return false;

            }
        }

        private static void CreateLogEntryError(Exception ex)
        {
            var settings = System.Configuration.ConfigurationManager.AppSettings;

            LogEntry logEntry = new LogEntry();
            logEntry.EventId = Convert.ToInt32(MaintenaceServiceEventTypes.Error, CultureInfo.InvariantCulture);
            logEntry.Message = String.Format(CultureInfo.CurrentCulture, Properties.Resources.ErrorSource, ex.Message, ex.Source);
            logEntry.Categories.Add("Error");
            logEntry.Priority = Convert.ToInt32(MaintenacePriorityMessage.High, CultureInfo.InvariantCulture);
            logEntry.Severity = TraceEventType.Error;
            logEntry.Title = String.Format(CultureInfo.CurrentCulture, "{1} - Error : {0}", ex.Message, settings.Get("ServiceDisplayName"));
            Logger.Write(logEntry);
        }

        private static void CreateLogEntryMessage(string title, string message, MaintenaceServiceEventTypes eventId,
            List<string> categories, MaintenacePriorityMessage priority, TraceEventType severity)
        {

            var settings = System.Configuration.ConfigurationManager.AppSettings;

            LogEntry logEntry = new LogEntry();
            logEntry.EventId = Convert.ToInt32(eventId,CultureInfo.InvariantCulture );
            logEntry.Message = message;
            foreach (var category in categories)
            {
                logEntry.Categories.Add(category);
            }
            logEntry.Priority = Convert.ToInt32(priority, CultureInfo.InvariantCulture);
            logEntry.Severity = severity;
            logEntry.Title = String.Format(CultureInfo.CurrentCulture,"{0} - {1}", settings.Get("ServiceDisplayName"), title);
            Logger.Write(logEntry);
        }
        

        protected override void OnStop()
        {
            CreateLogEntryMessage(Properties.Resources.Stop, String.Format(CultureInfo.CurrentCulture, Properties.Resources.ServiceStop),
              MaintenaceServiceEventTypes.GeneralInfo, categoriesInfo, MaintenacePriorityMessage.Low, TraceEventType.Information);

        }
    }
}
